﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;
using AgateLib.DisplayLib;
using AgateLib.Geometry;
using AgateLib.InputLib;
using AiAsteriods.Game.Entities.Agent;
using AiAsteriods.Game.Entities.Base;
using AiAsteriods.Game.Entities.Enemies;
using AiAsteriods.Game.Entities.Projectile;
using AiAsteriods.Game.Tools;

namespace AiAsteriods.Game.State {
  class GameState : GameStateAbstract {
    private double score = 0;
    private int timeToWeaponCanFire = 0;
    private int enemySpawnDirection = 0;
    private int counter = 0;
    private Random random;
    private FontSurface fontSmall;
    private FontSurface fontMenu;
    private FontSurface fontScore;
    private int gameOverWaitTime;
    private int gameOverMaxWaitTime;

    public int NumEnemies {
      get {
        int numEnemies = 0;
        for (int i =0; i < Entities.Count; i++) {
          if (Entities[i] is Enemy)
            numEnemies++;
        }
        return numEnemies;
      }
    }

    public GameState(ResourceManager rm, GameStart gs) : base(rm, gs) {
      random = new Random((int)AgateLib.Timing.TotalMilliseconds);
      gameOverMaxWaitTime = Global.GameStart.Config.AutoResetWait;
      gameOverWaitTime = gameOverMaxWaitTime;
    }

    override public void InitState() {
      // different fonts used in game
      fontSmall = new FontSurface("Verdana", 10);
      fontMenu = new FontSurface("Verdana", 9);
      fontScore = new FontSurface("Verdana", 13);

      Color c = new Color();
      c.R = (byte)255;
      c.G = (byte)200;
      c.B = (byte)100;
      c.A = (byte)255;
      fontScore.Color = c;

      // 'static' entities 
      player = new Player(0, false, DecidePathFinding.Decide, rm.GetSprite(SpriteType.Player), gs.ScreenWidth / 2, gs.ScreenHeight / 2, 0, 0, 10, 20, this);

      AddEntity(player);

      StateGrid.Init(1);
      MNodeFactory.Init();
    }

    override public void UpdateState(int delta) {
      if (Player1.currentLife > 0) {
        base.UpdateState(delta);
        counter += delta;
        EnemyMaker();

        CollisionDetect();
        timeToWeaponCanFire -= delta;
      }

      if (Keyboard.Keys[KeyCode.Escape]) {
        Application.Exit();
      }
    }

    public override void DrawState() {
      base.DrawState();
      fontSmall.DrawText(gs.ScreenWidth - 300, 0 + 10, "  " + (1000 / gs.GetDelta) + " fps, " + " enemies: " + NumEnemies);

      // draw UI
      fontScore.DrawText(20, 15, "Score: " + (int)score);
      fontSmall.DrawText(20, 35, "Level: " + Global.GameStart.Config.EnemyCongestion);
      if (Player1.currentLife < 0) {
        fontScore.DrawText(gs.ScreenWidth / 2 - 130, gs.ScreenHeight / 2 - 100, "GAME OVER, press R to restart");
        if (Global.GameStart.Config.AutoReset) {
          gameOverWaitTime--;
          if (gameOverWaitTime <= 0) {
            gameOverWaitTime = gameOverMaxWaitTime;
            gs.ResetGame();
          }
        }
        if (Keyboard.Keys[KeyCode.R]) {
          gs.ResetGame();
        }
      }
      if (Global.GameStart.Config.EnemyCongestion == 0) {
        fontScore.DrawText(gs.ScreenWidth / 2 - 70, gs.ScreenHeight / 2 - 100, "Get Ready!!");
      }
    }

    private void CollisionDetect() {
      EntityAbstract e1, e2;
      for (int k = 0; k < entities.Count; k++) {
        for (int l = k + 1; l < entities.Count; l++) {
          e1 = (EntityAbstract)entities[k];
          e2 = (EntityAbstract)entities[l];
          if (e1.CollisionTest(e2)) {
            e1.Collide(e2);
            e2.Collide(e1);
          }
        }
      }
    }

    private void EnemyMaker() {
      /*
       * All *original* enemeies made outside screen
       * enmeies can however spawn other enemeies
       */
      if ((entities.Count <= (Global.GameStart.Config.EnemyCongestion + 5)) && Global.GameStart.Config.EnemyCongestion > 0) {
        if (counter > 50) {
          if (random.Next(100) > 90) {
            enemySpawnDirection = random.Next(5);
          }

          int x= 0, y = 0, rotation = 0;
          // spawn from top
          if (enemySpawnDirection == 0) {
            x = random.Next(gs.ScreenWidth);
            y = -200;

            rotation = 180;
          }
          // spawn from right
          if (enemySpawnDirection == 1) {
            x = gs.ScreenWidth + 200;
            y = random.Next(gs.ScreenHeight);
            rotation = -90;
          }
          // spawn from bottom
          if (enemySpawnDirection == 2) {
            x = random.Next(gs.ScreenWidth);
            y = gs.ScreenHeight + 200;
            rotation = -180;
          }
          // spawn from left
          if (enemySpawnDirection == 3) {
            x = -200;
            y = random.Next(gs.ScreenHeight);
            rotation = 90;
          }
          if (enemySpawnDirection <= 3) {
            EntityAbstract ae;
            ae = new Enemy(rm.GetSprite(SpriteType.Enemy), x, y, Global.GameStart.Config.EnemySpeed, 0, 20, 10, this);
            ae.Rotation = rotation;

            AddEntity(ae);
          }
          counter = 0;
        }
      }
    }

    public override void AddScoreForTime(int delta) {
      if (Player1.currentLife > 0) {
        score += (delta / 1000.0) * Global.GameStart.Config.ScorePerSecond;
      }
    }

    public override void AddScoreForKill() {
      score += Global.GameStart.Config.ScorePerKill;
    }

    private void DrawDots() {
      EntityAbstract e;
      for (int k = 0; k < entities.Count; k++) {
        e = (EntityAbstract)entities[k];
        Display.FillRect(new Rectangle((int)e.X - 1, (int)e.Y - 1, 2, 2), Color.White);
        if (e.ICollidedWith() != null) {
          Display.DrawLine((int)e.X, (int)e.Y, (int)e.ICollidedWith().X, (int)e.ICollidedWith().Y, Color.Red);
        }
      }
    }

    public override object Clone() {
      GameState clone = new GameState(rm, gs);
      clone.entities = new System.Collections.ArrayList();
      clone.activeState = activeState;
      clone.enemySpawnDirection = enemySpawnDirection;
      Player p = this.Player1;
      clone.player = p; //      new Player(p.PlayerNum, true, p.Decide, rm.GetSprite(SpriteType.Player), (int)p.X, (int)p.Y, p.Speed, p.Rotation, p.Radius, p.CollisionDamage, clone);
      foreach (EntityAbstract entity in entities) {
        if (entity is Enemy) {
          Enemy s = entity as Enemy;
          clone.entities.Add(new Enemy(rm.GetSprite(SpriteType.Enemy), (int)s.X, (int)s.Y, s.Speed, s.Rotation, s.Radius, s.CollisionDamage, clone));
        }
      }

      return clone;
    }
  }
}
